//
//  AutomationDataManager.m
//  trongvm
//
//  Created by Phan Ba Minh on 6/15/12.
//  Copyright (c) 2012 kidbaw. All rights reserved.
//

#import "AutomationDataManager.h"
#import "UserDataManager.h"
#import "AppViewController.h"
#import "SBJSON.h"

@implementation AutomationDataManager
- (id)init
{
    self = [super init];
    if (self) {
        _APIRequester = [APIRequester new];
        _APIRequesterKardBuilder = [APIRequester new];
        
        _automationDataManagerStep = enumAutomationDataManagerStep_UpdateUserLocation;
        
        _locationManager = [[CLLocationManager alloc] init];
        _locationManager.delegate = self;
        _locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
        _locationManager.distanceFilter = 10;
        
        if (![UserDataManager Shared].userLocation) {
            [UserDataManager Shared].userLocation = [[CLLocation alloc] initWithLatitude:STRING_LOCATION_LATITUDE_DEFAULT.doubleValue longitude:STRING_LOCATION_LONGTITUDE_DEFAULT.doubleValue];
        }
        
//        [self updateUserLocationService];
        
        _pageIndexTemplate = 1;
        _pageIndexGraphic = 1;
        _pageIndexMeKards = 1;
        _locationState = enumLocationState_Stop;
        _locationTimeOut = [NSDate date];
        _isFirstTime = TRUE;
        _alertLocationService = [[UIAlertView alloc] initWithTitle:@"" message:STRING_ALERT_MESSAGE_TURN_ON_LOCATION_SERVICE delegate:self cancelButtonTitle:STRING_ALERT_OK otherButtonTitles:nil];
        _alertRequestFailed = [[UIAlertView alloc] initWithTitle:STRING_ALERT_CONNECTION_ERROR_TITLE message:STRING_ALERT_CONNECTION_ERROR delegate:self cancelButtonTitle:STRING_ALERT_OK otherButtonTitles:nil];  
    }
    return self;
}

- (void)dealloc
{
}

#pragma mark - Actions

- (void)cancelRequest {
    _delegate = nil;
    [_APIRequester cancelRequest];
    _automationDataManagerStep = enumAutomationDataManagerStep_CheckingForNext;
}

- (void)reloadAllDataWithDataIsReady:(enumAutomationDataIsReady)isReady andDelegate:(id<AutomationDataManagerProtocol>)delegate{
    NSLog(@"reloadAllDataWithDataIsReady: %i, %@", isReady, [[delegate class] description]);
    
    if (isReady == enumAutomationDataIsReady_ForHome_BeforeEntering || isReady == enumAutomationDataIsReady_ForRegister_CreatingAccount) {
        _dataIsReady = isReady;
        _delegate = delegate;
        _automationDataManagerStep = enumAutomationDataManagerStep_UpdateUserLocation;
    }
    else if (isReady == enumAutomationDataIsReady_ForKonnect_UpdateUserLocation) {
//        [self updateUserLocationService];
        
        _dataIsReady = isReady;
        _delegate = delegate;
        _automationDataManagerStep = enumAutomationDataManagerStep_UpdateUserLocation;
    }
    else {
        _dataIsReady = isReady;
        _delegate = delegate;
        _automationDataManagerStep = enumAutomationDataManagerStep_UpdateUserLocation;
    }
}

- (void)requestAPIWithAutomationDataManagerStep:(enumAutomationDataManagerStep)type {
    switch (type) {
        case enumAutomationDataManagerStep_UpdateUserLocation:
        {
            [self startUpdateLocationService];
            BOOL gpsIsAllowed = NO;
            if (CLLocationManager.authorizationStatus == kCLAuthorizationStatusRestricted || CLLocationManager.authorizationStatus == kCLAuthorizationStatusDenied)
            {
                gpsIsAllowed = NO;
            }
            else {
                gpsIsAllowed = YES;
            }
            
            NSMutableDictionary  *params = [NSMutableDictionary new];
            
            if ([[UIDevice currentDevice] isSimulator]) {
                // Hard Code
                [UserDataManager Shared].userLocation = [[CLLocation alloc] initWithLatitude:STRING_LOCATION_LATITUDE_DEFAULT.doubleValue longitude:STRING_LOCATION_LONGTITUDE_DEFAULT.doubleValue];
            }
            
            NSString *loc = [NSString stringWithFormat:@"%f,%f", [UserDataManager Shared].userLocation.coordinate.longitude, [UserDataManager Shared].userLocation.coordinate.latitude];
            [params setObject:loc forKey:STRING_REQUEST_KEY_LOC];
            
            NSString *strURL = [NSString stringWithFormat:@"%@/%@", STRING_REQUEST_URL_USER_UPDATE_LOCATION_AND_GPS, [UserDataManager Shared].userID];
            
            [[APIRequester Shared] requestWithType:ENUM_API_REQUEST_TYPE_USER_UPDATE_LOCATION andRootURL:strURL andPostMethodKind:YES andParams:params andDelegate:self];
            break;
        }
        default:
            break;
    }
}

- (void)update {
    if (![UserDataManager Shared].loginStatus || _dataIsReady == enumAutomationDataIsReady_Invalid) {
//        NSLog(@"AutomationDataManager: can not load user's data automatically");
        _dataIsReady = enumAutomationDataIsReady_Invalid;
        return;
    }
    
    switch (_automationDataManagerStep) {
        case enumAutomationDataManagerStep_UpdateUserLocation:
        {
            _requestTimer =  CFAbsoluteTimeGetCurrent();
            _checkingNetworkTimer =  CFAbsoluteTimeGetCurrent();
            
            [self requestAPIWithAutomationDataManagerStep:_automationDataManagerStep];
            _automationDataManagerStep = enumAutomationDataManagerStep_UpdateUserLocation_Waiting;
            break;
        }
        case enumAutomationDataManagerStep_UpdateUserLocation_Failed:
        {
            _automationDataManagerStep = enumAutomationDataManagerStep_UpdateUserLocation;
            break;
        }
        case enumAutomationDataManagerStep_UpdateUserLocation_Finished:
        {
            _automationDataManagerStep = enumAutomationDataManagerStep_CheckingForNext;
            break;
        }
        case enumAutomationDataManagerStep_CheckingForNext:
        {
            if (CFAbsoluteTimeGetCurrent() - _requestTimer > TIMER_AUTOMATION_UPDATING) {
                _automationDataManagerStep = enumAutomationDataManagerStep_UpdateUserLocation;
                _dataIsReady = enumAutomationDataIsReady_ForAutomation;
            }
            break;
        }
        case enumAutomationDataManagerStep_CheckingForNetwork:
        {
            if (([ASIHTTPRequest isNetworkReachable] || CFAbsoluteTimeGetCurrent() - _checkingNetworkTimer > TIMER_AUTOMATION_CHECKING_NETWORK) && !_alertCheckingNetwork_Showing) {
                _checkingNetworkTimer =  CFAbsoluteTimeGetCurrent();
                _dataIsReady = enumAutomationDataIsReady_ForAutomation;
                _automationDataManagerStep = _previousStep;
            }
            break;
        }
        default:
            break;
    }
}

#pragma mark - APIRequesterProtocol

- (void)requestFinished:(ASIHTTPRequest *)request andType:(ENUM_API_REQUEST_TYPE)type {
    NSLog(@"AutomationDataManager requestFinished %@, request.responseStatusCode: %i", request.responseString, request.responseStatusCode);
    
    NSError *error;
    SBJSON *sbJSON = [SBJSON new];
    
    if (![sbJSON objectWithString:[request responseString] error:&error] || request.responseStatusCode != 200 || !request) {
        // MinhPB 2012/10, should not return then get the old step to help the System understand
        ALERT(STRING_ALERT_CONNECTION_ERROR_TITLE, STRING_ALERT_SERVER_ERROR);
        
        if ([_delegate respondsToSelector:@selector(didRequestFailedWithDataIsReady:)]) {
            [_delegate didRequestFailedWithDataIsReady:_dataIsReady];
            _delegate = nil;
        }
        
        if (_dataIsReady == enumAutomationDataIsReady_ForAutomation) {
            _alertCheckingNetwork_Showing = YES;
            
            if (type == ENUM_API_REQUEST_TYPE_USER_UPDATE_LOCATION) {
                _previousStep = enumAutomationDataManagerStep_UpdateUserLocation_Failed;
            }
            _automationDataManagerStep = enumAutomationDataManagerStep_CheckingForNetwork;
        }
        else {
            _automationDataManagerStep = enumAutomationDataManagerStep_CheckingForNext;
        }
        return;
    }
    
    if ([_delegate respondsToSelector:@selector(didRequestFailedWithDataIsReady:)]) {
        [_delegate didRequestFinishedWithDataIsReady:_dataIsReady];
        _delegate = nil;
    }
    
    if (type == ENUM_API_REQUEST_TYPE_USER_UPDATE_LOCATION) {
        _automationDataManagerStep = enumAutomationDataManagerStep_UpdateUserLocation_Finished;
        
        NSMutableDictionary *dicJson = [sbJSON objectWithString:[request responseString] error:&error];
        
        [UserDataManager Shared].userFullName = [dicJson objectForKey:STRING_RESPONSE_KEY_NAME];
        [UserDataManager Shared].userEmail = [dicJson objectForKey:STRING_RESPONSE_KEY_EMAIL];
        [[UserDataManager Shared] save];
    }
}

- (void)requestFailed:(ASIHTTPRequest *)request andType:(ENUM_API_REQUEST_TYPE)type {
    NSLog(@"AutomationDataManager requestFinished %@, request.responseStatusCode: %i", request.responseString, request.responseStatusCode);
    // MinhPB 2012/10, should not return then get the old step to help the System understand
    if ([_delegate respondsToSelector:@selector(didRequestFailedWithDataIsReady:)]) {
        [_delegate didRequestFailedWithDataIsReady:_dataIsReady];
        _delegate = nil;
    }
    
    if (!_alertRequestFailed.visible) {
        [_alertRequestFailed show];
    }
    
    if (_dataIsReady == enumAutomationDataIsReady_ForAutomation) {
        _alertCheckingNetwork_Showing = YES;
        
        if (type == ENUM_API_REQUEST_TYPE_USER_UPDATE_LOCATION) {
            _previousStep = enumAutomationDataManagerStep_UpdateUserLocation_Failed;
        }
        _automationDataManagerStep = enumAutomationDataManagerStep_CheckingForNetwork;
    }
    else {
        _automationDataManagerStep = enumAutomationDataManagerStep_CheckingForNext;
    }
}

#pragma mark - CLLocationManagerDelegate

/*
- (void)updateUserLocationService {
    // Only allow user request location after amount time default is 2 mins
    if (![self isAllowGetCurrentLocationTimer]) {
        return;
    }
    
    if (CLLocationManager.authorizationStatus == kCLAuthorizationStatusRestricted || CLLocationManager.authorizationStatus == kCLAuthorizationStatusDenied)
    {
        if (!_alertLocationService.visible) {
            [_alertLocationService show];
        }
    }
    else {
        //[_locationManager stopUpdatingLocation];
        //[_locationManager startUpdatingLocation];
        [self startUpdateLocationService];
    }
}
*/

- (void)startMonitoringSignificantLocationChanges {
    if (CLLocationManager.authorizationStatus == kCLAuthorizationStatusRestricted || CLLocationManager.authorizationStatus == kCLAuthorizationStatusDenied)
    {
        if (!_alertLocationService.visible) {
            [_alertLocationService show];
        }
    }
    else {
        if (_locationState == enumLocationState_Standard_Running) {
            [self stopUpdateLocationService];
        }
        [_locationManager startMonitoringSignificantLocationChanges];
        _locationState = enumLocationState_SLC_Running;
    }
}


- (void)stopMonitoringSignificantLocationChanges {
    if (CLLocationManager.authorizationStatus == kCLAuthorizationStatusRestricted || CLLocationManager.authorizationStatus == kCLAuthorizationStatusDenied)
    {
        if (!_alertLocationService.visible) {
            [_alertLocationService show];
        }
    }
    else {
        [_locationManager stopMonitoringSignificantLocationChanges];
        _locationState = enumLocationState_SLC_Stop;
    }
}

- (void)startUpdateLocationService {
    // MinhPB force updating 
    // Only allow user request location after amount time default is 2 mins
    if (![self isAllowGetCurrentLocationTimer]) {
        return;
    }
    
    if (CLLocationManager.authorizationStatus == kCLAuthorizationStatusRestricted || CLLocationManager.authorizationStatus == kCLAuthorizationStatusDenied)
    {
        if (!_alertLocationService.visible) {
            [_alertLocationService show];
        }
    }
    else {
        if (_locationState == enumLocationState_SLC_Running) {
            [self stopMonitoringSignificantLocationChanges];
        }
        [_locationManager startUpdatingLocation];
        _locationState = enumLocationState_Standard_Running;
    }
}

- (void)stopUpdateLocationService {
    if (CLLocationManager.authorizationStatus == kCLAuthorizationStatusRestricted || CLLocationManager.authorizationStatus == kCLAuthorizationStatusDenied)
    {
        if (!_alertLocationService.visible) {
            [_alertLocationService show];
        }
    }
    else {
        [_locationManager stopUpdatingLocation];
         _locationState = enumLocationState_Standard_Stop;
    }
}

-(void) sendBackgroundLocationToServer:(CLLocation *)location
{
    // REMEMBER. We are running in the background if this is being executed.
    // We can't assume normal network access.
    // bgTask is defined as an instance variable of type UIBackgroundTaskIdentifier
    
    // Note that the expiration handler block simply ends the task. It is important that we always
    // end tasks that we have started.
    
    bgTask = [[UIApplication sharedApplication]
              beginBackgroundTaskWithExpirationHandler:
              ^{
                  [[UIApplication sharedApplication] endBackgroundTask:bgTask];
                   }];
                  
                  // ANY CODE WE PUT HERE IS OUR BACKGROUND TASK
                  
                  // For example, I can do a series of SYNCHRONOUS network methods (we're in the background, there is
                  // no UI to block so synchronous is the correct approach here).
                  
                  // ...
                  
                  // AFTER ALL THE UPDATES, close the task
                  
                  if (bgTask != UIBackgroundTaskInvalid)
                  {
                      [[UIApplication sharedApplication] endBackgroundTask:bgTask];
                       bgTask = UIBackgroundTaskInvalid;
                       
                  }
}

- (void)updateLocalUserLocation:(CLLocation *)location {
    // MinhPB 2012/10/26
    if (location.coordinate.latitude == 0 || location.coordinate.longitude == 0) {
        return;
    }
    
//    NSLog(@"-updateLocalUserLocation-_locationState=%i",_locationState);
    [UserDataManager Shared].userLocation = location;
    [[UserDataManager Shared] save];
    
    // If it's a relatively recent event, turn off updates to save power
    NSDate* eventDate = location.timestamp;
    NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
    if (abs(howRecent) < 15.0) {
        // If the event is recent, do something with it.
//        NSLog(@"latitude %+.6f, longitude %+.6f\n",
//              location.coordinate.latitude,
//              location.coordinate.longitude);
        
        
        CLGeocoder * geoCoder = [[CLGeocoder alloc] init];
        [geoCoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
            // STOP TRACKING USER LOCATION TO SAVE BATTERRY ONCE THE LOCATION FIX
            //[self stopUpdateLocationService];
            if (_locationState == enumLocationState_Standard_Running) {
                //[_locationManager stopUpdatingLocation];
                //[self stopUpdateLocationService];
                [self startMonitoringSignificantLocationChanges];
            }
            
            [UserDataManager Shared].currentPlaceMark = [placemarks objectAtIndex:0];
            [[UserDataManager Shared] save];
        }];
    }
}


-(BOOL)isAllowGetCurrentLocationTimer {
    // Only allow user request location after amount time default is 2 mins
    NSTimeInterval howRecent = [_locationTimeOut timeIntervalSinceNow];
    if (abs(howRecent) < TIMER_LOCATION_ALLOW_TO_UPDATE && !_isFirstTime) {
        return FALSE;
    } else {
        // Update current time
        _locationTimeOut = [NSDate date];
        _isFirstTime = FALSE;
        return TRUE;
    }
}

// decaptered in iOS5
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
    
    //[_locationManager stopUpdatingLocation];
    
  //  NSLog(@" didUpdateToLocation %f, %f", newLocation.coordinate.latitude, newLocation.coordinate.longitude);
//        ALERT(@"", [NSString stringWithFormat:@"test location: %f", [newLocation distanceFromLocation:userLocation]]);
    
    //[UserDataManager Shared].userLocation = newLocation;
    //[[UserDataManager Shared] save];
    
    [self updateLocalUserLocation:newLocation];
    /*
    // Get Currrent Placemark
    CLGeocoder * geoCoder = [[CLGeocoder alloc] init];
    [geoCoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *placemarks, NSError *error) {
        //NSString * location = ([placemarks count] > 0) ? [[placemarks objectAtIndex:0] locality] : @"Not Found";
        
        //NSLog(@"----------Place marks = %@", location);
        
        
        // STOP TRACKING USER LOCATION TO SAVE BATTERRY ONCE THE THE LOCATION FIX
        [_locationManager stopUpdatingLocation];
        
        [UserDataManager Shared].currentPlaceMark = [placemarks objectAtIndex:0];
        [[UserDataManager Shared] save];
        
        //NSString *isoCountryCodetext = placemark.ISOcountryCode;
        //NSString *countrytext = placemark.country;
        //NSString *postalCodetext= placemark.postalCode;
        //NSString *adminAreatext=placemark.administrativeArea;
        //NSString *subAdminAreatext=placemark.subAdministrativeArea;
        //NSString *localitytext=placemark.locality;
        //NSString *subLocalitytext=placemark.subLocality;
        //NSString *thoroughfaretext=placemark.thoroughfare;
        //NSString *subThoroughfaretext=placemark.subThoroughfare;
        
        
        //NSLog(@"-------1---Place marks = %@", [UserDataManager Shared].currentPlaceMark);
        //NSLog(@"-------2---Place marks = %@----%@-----%@-----%@", [UserDataManager Shared].currentPlaceMark.locality,[UserDataManager Shared].currentPlaceMark.subLocality,[UserDataManager Shared].currentPlaceMark.subAdministrativeArea,[UserDataManager Shared].currentPlaceMark.administrativeArea);
        
        //region.text=placemark.region;
        
        
    }];
    */
    
}


// Delegate method from the CLLocationManagerDelegate protocol.
- (void)locationManager:(CLLocationManager *)manager
     didUpdateLocations:(NSArray *)locations
{
    
    BOOL isInBackground = NO;
    if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground)
    {
        isInBackground = YES;
    }
    
    // Handle location updates as normal, code omitted for brevity.
    // The omitted code should determine whether to reject the location update for being too
    // old, too close to the previous one, too inaccurate and so forth according to your own
    // application design.
    
    if (isInBackground)
    {
        //[self sendBackgroundLocationToServer:newLocation];
    }
    else
    {
        // ...
    }
    
    CLLocation* location = [locations lastObject];
    [self updateLocalUserLocation:location];    
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
    NSLog(@" didFailWithError ");
//    [_locationManager stopUpdatingLocation];
    
//    ALERT(@"", STRING_ALERT_MESSAGE_TURN_ON_LOCATION_SERVICE);
}

- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
    NSLog(@" didChangeAuthorizationStatus ");
    if (status == kCLAuthorizationStatusRestricted || status == kCLAuthorizationStatusDenied)
    {
        if (!_alertLocationService.visible) {
            [_alertLocationService show];
        }
    }
    else {
        [_alertLocationService dismissWithClickedButtonIndex:0 animated:YES];
    }
}

static AutomationDataManager *m_Instance;
+ (AutomationDataManager *)Shared
{
    if (!m_Instance) {
        m_Instance = [AutomationDataManager new];
    }
    return m_Instance;
}

#pragma mark - UIAlertViewDelegate

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    _alertCheckingNetwork_Showing = NO;
}

@end
